package kin.converter;

import java.beans.PropertyDescriptor;   
import java.lang.reflect.InvocationTargetException;  
import java.lang.reflect.ParameterizedType;  
  
import org.apache.commons.beanutils.BeanUtilsBean;  
import org.apache.commons.beanutils.ContextClassLoaderLocal;  
import org.apache.commons.beanutils.Converter;  
import org.apache.commons.beanutils.DynaBean;  
import org.apache.commons.beanutils.DynaClass;  
import org.apache.commons.beanutils.DynaProperty;  
import org.apache.commons.beanutils.PropertyUtilsBean;  
  
public class ARPBeanUtilsBean extends BeanUtilsBean {  
  
    public ARPBeanUtilsBean() {  
        super(new ARPConvertUtilsBean(), new PropertyUtilsBean());  
    }  
  
    public static synchronized BeanUtilsBean getInstance() {  
        return ((BeanUtilsBean) new ContextClassLoaderLocal() {  
            // Creates the default instance used when the context classloader is  
            // unavailable  
            protected Object initialValue() {  
                return new ARPBeanUtilsBean();  
            }  
        }.get());  
    }  
  
    @Override  
    public void copyProperty(Object bean, String name, Object value)  
            throws IllegalAccessException, InvocationTargetException {  
         
        Object target = bean;  
        int delim = name.lastIndexOf(46);  
        if (delim >= 0) {  
            try {  
                target = getPropertyUtils().getProperty(bean,name.substring(0, delim));  
            } catch (NoSuchMethodException e) {  
                return;  
            }  
            name = name.substring(delim + 1);  
        }  
  
        String propName = null;  
        Class type = null;  
        int index = -1;  
        String key = null;  
  
        propName = name; 
        
        //System.out.println("name:"+name);
       // System.out.println("propName:"+propName);
        int i = propName.indexOf(91);  
        if (i >= 0) {  
            int k = propName.indexOf(93);  
            try {  
                index = Integer.parseInt(propName.substring(i + 1, k));  
            } catch (NumberFormatException e) {  
            }  
            propName = propName.substring(0, i);  
        }  
        int j = propName.indexOf(40);  
        if (j >= 0) {  
            int k = propName.indexOf(41);  
            try {  
                key = propName.substring(j + 1, k);  
            } catch (IndexOutOfBoundsException e) {  
            }  
            propName = propName.substring(0, j);  
        }  
  
        if (target instanceof DynaBean) {  
            DynaClass dynaClass = ((DynaBean) target).getDynaClass();  
            DynaProperty dynaProperty = dynaClass.getDynaProperty(propName);  
            if (dynaProperty == null) {  
                return;  
            }  
            type = dynaProperty.getType();  
        } else {  
            PropertyDescriptor descriptor = null;  
            try {  
                descriptor = getPropertyUtils().getPropertyDescriptor(target,name);  
  
                if (descriptor == null)  
                    return;  
            } catch (NoSuchMethodException e) {  
                return;  
            }  
            type = descriptor.getPropertyType();  
            if (type == null) {  
                return;  
            }  
        }  
  
        if (index >= 0) {  
            Converter converter = getConvertUtils().lookup(type.getComponentType());  
            if (converter != null) {  
                value = converter.convert(type, value);  
            }  
            try {  
                getPropertyUtils().setIndexedProperty(target, propName, index, value);  
            } catch (NoSuchMethodException e) {  
                throw new InvocationTargetException(e, "Cannot set " + propName);  
            }  
        } else if (key != null) {  
            try {  
                getPropertyUtils().setMappedProperty(target, propName, key, value);  
            } catch (NoSuchMethodException e) {  
                throw new InvocationTargetException(e, "Cannot set " + propName);  
            }  
        } else {  
            Converter converter = getConvertUtils().lookup(type);  
            if (converter != null) {  
                if (converter instanceof ParameterizedTypeConverter) {  
                    try {  
                        ParameterizedType targetActualType = (ParameterizedType) target.getClass().getDeclaredField(propName).getGenericType();  
                        Class<?> targetActualClass = (Class<?>) targetActualType.getActualTypeArguments()[0];  
                        value = ((ParameterizedTypeConverter) converter)  
                                .convert(type, targetActualClass, value);  
                    } catch (Exception e) {  
                        return;  
                    }  
  
                } else {  
                    try {  
                        value = converter.convert(type, value);  
                    } catch (Exception e) {  
                        return;  
                    }  
                }  
            }else {  
                try {  
                    value = ARPBeanUtils.cloneBean(type, value);  
                } catch (Exception e) {  
                    return;  
                }  
            }  
  
            try {  
                getPropertyUtils().setSimpleProperty(target, propName, value);  
            } catch (NoSuchMethodException e) {  
                throw new InvocationTargetException(e, "Cannot set " + propName);  
            }  
        }  
    }  
}  